<template>
  <el-row
    :gutter="0"
    class="container"
    v-loading.fullscreen.lock="fullscreenLoading"
  >
    <el-col :span="7" class="left-nav">
      <div class="nav-list">
        <div
          class="nav-item"
          v-for="row of navList"
          :key="row.id"
          :id="row.ref"
          @click="changeView(row)"
        ></div>
      </div>
    </el-col>
    <el-col :span="17" class="right-content">
      <div class="user-preference">
        <el-button type="primary" @click="playMusic">播放</el-button>
        <el-button type="danger" @click="pauseMusic">暂停</el-button>
      </div>
      <div ref="bigDOM" class="big_dom"></div>
    </el-col>
  </el-row>
</template>

<script setup lang="ts">
  import { ElLoading } from "element-plus";
  import * as THREE from "three";
  import { GLTF, OrbitControls } from "three/examples/jsm/Addons.js";
  import { GLTFLoader } from "three/examples/jsm/loaders/GLTFLoader";
  import { inject, onMounted, ref } from "vue";

  interface Vector {
    x: number;
    y: number;
    z: number;
  }

  interface NavItem {
    id: number;
    type: string;
    ref: string;
    position: Vector;
    scale: Vector;
  }

  ElLoading.service({
    lock: true,
    text: "小米Su7模型加载中...",
    background: "rgba(0, 0, 0, 0.7)",
  });

  const music = new Audio('https://lv-sycdn.kuwo.cn/0bba2121ccef2f6f875d73d7393de15c/68fc92e8/resource/30106/trackmedia/M500002OqCe33koIGB.mp3');
  
  music.loop = true;

  const navList = ref([
    {
      id: 1,
      type: "车左",
      ref: "car_left",
      position: { x: -5, y: 1.5, z: 0 },
      scale: { x: 0.95, y: 0.95, z: 0.95 },
    },
    {
      id: 2,
      type: "车右",
      ref: "car_right",
      position: { x: 5, y: 1.5, z: 0 },
      scale: { x: 0.95, y: 0.95, z: 0.95 },
    },
    {
      id: 3,
      type: "车尾",
      ref: "car_tail",
      position: { x: 0, y: 1.5, z: -5 },
      scale: { x: 0.95, y: 0.95, z: 0.95 },
    },
    {
      id: 4,
      type: "车头",
      ref: "car_head",
      position: { x: 0, y: 1.5, z: 5 },
      scale: { x: 0.95, y: 0.95, z: 0.95 },
    },
  ]);

  const bigDOM = ref<HTMLElement | null>(null);
  const navListDOM = ref<HTMLElement[]>();
  const fullscreenLoading = ref(true);
  const autoRotate = ref(false);

  const baseUrl = inject('baseUrl');

  const defaultPosition: Vector = { x: 0, y: 0, z: 0 };
  const defaultScale: Vector = { x: 1, y: 1, z: 1 };
  const defaultTarget: Vector = { x: 0, y: 0, z: 0 };

  const load3DModel = (
    element: HTMLElement,
    position: Vector = defaultPosition,
    scale: Vector = defaultScale,
    target: Vector = defaultTarget
  ): void => {
    const scene = new THREE.Scene();
    const camera = new THREE.PerspectiveCamera(
      50,
      element.clientWidth / element.clientHeight,
      0.1,
      1000
    );

    camera.position.set(position.x, position.y, position.z);
    camera.lookAt(new THREE.Vector3(position.x, position.y, position.z)); // 目标点为中心

    const renderer = new THREE.WebGLRenderer({
      antialias: true,
      alpha: true,
    });
    renderer.setSize(element.clientWidth, element.clientHeight);
    element.appendChild(renderer.domElement);

    const textureLoader = new THREE.TextureLoader();
    textureLoader.load(`bg.jpg`, (texture) => {
      scene.background = texture;
    });

    const controls = new OrbitControls(camera, renderer.domElement);
    controls.target.set(target.x, target.y, target.z);
    controls.autoRotate = autoRotate.value;

    const light1 = new THREE.AmbientLight(0xffffff, 2);
    scene.add(light1);

    const directionalLight = new THREE.DirectionalLight(0xffffff, 2);
    directionalLight.position.set(5, 5, 5);
    scene.add(directionalLight);

    const loader = new GLTFLoader();

    loader.load(
      `3d-model.glb`,
      (gltf: GLTF) => {
        const model = gltf.scene;
        model.scale.set(scale.x, scale.y, scale.z);
        scene.add(model);
      },
      (xhr: ProgressEvent) => {
        if ((xhr.loaded / xhr.total) * 100 == 100) {
          fullscreenLoading.value = false;
        }
      },
      (error: ErrorEvent) => {
        console.error(error);
      }
    );

    const animate = () => {
      requestAnimationFrame(animate);
      controls.update();
      renderer.render(scene, camera);
    };
    animate();
  };

  const changeView = (row: NavItem) => {
    if (bigDOM.value) {
      bigDOM.value.firstChild?.remove();
      load3DModel(bigDOM.value, row.position);
    }
  };

  const playMusic = () => {
    music.play();
    autoRotate.value = true;
    loadAllModel();
  };

  const pauseMusic = () => {
    music.pause();
    autoRotate.value = false;
    loadAllModel();
  };

  onMounted(() => {
    loadAllModel();
  });

  const loadAllModel = async () => {
    navListDOM.value = Array.from(
      document.querySelectorAll(".nav-item")
    ) as HTMLElement[];

    for (const obj of navListDOM.value as HTMLElement[]) {
      navList.value.filter((item: NavItem) => {
        if (item.ref === obj.id) {
          load3DModel(obj, item.position, item.scale);
        }
      });
    }

    await load3DModel(
      bigDOM.value as HTMLElement,
      { x: 0, y: 2, z: 6 },
      defaultScale,
      {
        x: 0,
        y: 1.5,
        z: 0,
      }
    );
  };
</script>

<style lang="scss" scoped>
  .container {
    width: 100%;
    height: 100%;
  }

  .left-nav {
    width: 100%;
    height: 100vh;
    overflow-y: scroll;
  }

  .nav-list {
    height: 100%;
    display: flex;
    flex-direction: column;
    justify-content: start;
    align-items: center;
  }

  .nav-list > .nav-item {
    width: 100%;
    cursor: pointer;
    min-height: 250px;
  }

  .right-content {
    width: 100%;
    height: 100vh;
  }

  .big_dom {
    width: 100%;
    height: 100%;
  }

  .user-preference {
    position: absolute;
    top: 10px;
    right: 10px;
  }
</style>
